import datetime
import os

from django.contrib.auth.models import User
from django.db import models
from django.contrib import admin
from django.utils.html import format_html
from django.dispatch import receiver
from django.db.models.signals import pre_delete
from django.conf import settings
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError
from mptt.models import MPTTModel, TreeForeignKey
from django.utils.timezone import now
from mptt.models import MPTTModel, TreeManyToManyField


# Create your models here.
class BaseModel(models.Model):
    create_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")


class ArticleKeyword(BaseModel):
    text = models.CharField(verbose_name="关键词", max_length=100, db_index=True)
    value = models.IntegerField(verbose_name="篇数", default=0)

    def get_frequency(self):
        queryset = self.objects.all()
        frequency_dict = {}
        for keyword in queryset:
            frequency_dict[keyword.text] = keyword.article_set.count()
        return frequency_dict

    @admin.display(description="关键词")
    def keyword_preview(self):
        if self.text is not None:
            keyword_info = f'{self.text}'

        return format_html(
            f'<pre style="width:200px; white-space: pre-wrap; word-wrap: break-word;">{keyword_info}</pre>')

    @admin.display(description="篇数")
    def keyword_value_preview(self):

        keyword_info = f"{self.value} (有风险{self.article_set.filter(risk=Article.HAS_RISK).count()}篇)"

        return format_html(
            f'<pre style="width:200px; white-space: pre-wrap; word-wrap: break-word;">{keyword_info}</pre>')

    @admin.display(description="关键词")
    def keyword_preview(self):
        if self.text is not None:
            keyword_info = f'{self.text}'

        return format_html(
            f'<pre style="width:200px; white-space: pre-wrap; word-wrap: break-word;">{keyword_info}</pre>')

    @admin.display(description="关键词对应文章")
    def keyword_articles_preview(self):
        return format_html(
            f'<a style="width:200px;" href="/admin/ai/article/?keywords__basemodel_ptr__exact={self.id}">文章集合</a>')

    def __str__(self):
        return self.text

    class Meta:
        ordering = ('-value', '-id',)
        verbose_name_plural = "文章关键词"
        verbose_name = "文章关键词"


class UserKeywordFocus(BaseModel):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    event = models.CharField(verbose_name="事件名称", max_length=20, null=False, blank=False, default='默认事件名')
    config = models.JSONField(verbose_name="关键词配置", null=True, blank=True, default=None)

    @admin.display(description="用户")
    def user_preview(self):
        return self.user.username

    class Meta:
        # 去掉排序，解决第一次创建分类添加父分类时， target_tree_id 与 new_tree_id 错误的问题
        verbose_name_plural = "用户关注事件"
        verbose_name = "用户关注事件"

    def __str__(self):
        return self.event


class ArticleCategory(MPTTModel):
    name = models.CharField(max_length=50, unique=True)
    parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    description = models.CharField(max_length=200, blank=True, null=True)
    created_time = models.DateTimeField('创建时间', default=now)
    last_mod_time = models.DateTimeField('修改时间', default=now)

    class MPTTMeta:
        # 去掉排序，解决第一次创建分类添加父分类时， target_tree_id 与 new_tree_id 错误的问题
        parent_attr = 'parent'

    def __str__(self):
        return self.name

    class Meta:
        ordering = ("-last_mod_time", '-id')
        verbose_name_plural = "文章分类"
        verbose_name = "文章分类"


class StaticURLValidator:
    def __call__(self, value):
        if value.startswith(settings.STATIC_URL):
            url_validator = URLValidator()
        try:
            url_validator(value)
        except ValidationError:
            raise ValidationError('Invalid URL')


class Article(BaseModel):
    NO_RISK = '无'
    HAS_RISK = '有'
    RISK_CHOICE = [
        (NO_RISK, "无风险"),
        (HAS_RISK, "有风险"),
    ]

    title = models.CharField(verbose_name="标题", max_length=300)
    url = models.CharField(verbose_name="标题链接", max_length=300)
    thumb = models.CharField(verbose_name="缩略图地址", max_length=300, blank=True, null=True,
                             default=f"{settings.STATIC_URL}article_default_thumb.jpg")

    public_time = models.DateTimeField(verbose_name="发布时间")
    content = models.TextField(verbose_name="正文内容")
    abstract = models.TextField(verbose_name="摘要", null=True, blank=True, default=None)
    keywords = models.ManyToManyField(ArticleKeyword, verbose_name="关键词")
    keywords_raw = models.CharField(verbose_name="关键词原内容", help_text="用于关键词分词错误时，重置关键词分词信息",
                                    max_length=300, default='')
    category = TreeManyToManyField(ArticleCategory, verbose_name="分类", blank=True)
    categories_raw = models.CharField(verbose_name="分类原内容", help_text="用于导出文件，直接使用该字段", null=True,
                                      blank=True,
                                      max_length=50, default="")
    keyword_contents = models.TextField(verbose_name="关键内容", null=True, blank=True, default=None)
    risk = models.CharField(verbose_name="风险判断", max_length=6, default=NO_RISK, choices=RISK_CHOICE)
    author = models.CharField(verbose_name="作者", max_length=50, null=True, blank=True, default="")
    article_source = models.CharField(verbose_name="来源", max_length=50, null=True, blank=True, default="")

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        if self.thumb is None:
            self.thumb = f"{settings.STATIC_URL}article_default_thumb.jpg"

        super().save(*args, **kwargs)

    class Meta:
        verbose_name_plural = "文章"
        verbose_name = "文章"
        ordering = ("-public_time", '-updated_at', '-id')

    @admin.display(description="标题")
    def title_preview(self):
        return format_html(f'<div style="width:200px; padding:5px; word-wrap: break-word;">\
         {self.title} </div>')

    @admin.display(description="标题链接")
    def url_preview(self):
        return format_html(f'<a target="_blank" href="{self.url}"> {self.url} </>')

    @admin.display(description="缩略图")
    def thumb_preview(self):
        return format_html(f'<image style="height:105px;width:220px" src="{self.thumb}" />')

    @admin.display(description="摘要")
    def abstract_preview(self):
        return format_html(
            f'<pre style="width:200px; white-space: pre-wrap; word-wrap: break-word;">{self.abstract}</pre>')

    @admin.display(description="文章内容")
    def content_preview(self):
        return format_html('<pre style="width:300px;white-space: pre-wrap; word-wrap: break-word;\
         overflow: hidden;display: -webkit-box;-webkit-line-clamp: 3; -webkit-box-orient: vertical;text-overflow: ellipsis;"\
         title="{}">  {}<pre/>', self.content, self.content)

    @admin.display(description="关键词")
    def keywords_preview(self):
        return format_html(
            f'<pre style="width:100px; white-space: pre-wrap; word-wrap: break-word; font-weight:bold">\
                {", ".join(keyword.text for keyword in self.keywords.all())}</pre>')

    @admin.display(description="分类")
    def category_preview(self):
        category_info = ""
        for category in self.category.all():
            category_level = category.get_ancestors(include_self=True, ascending=False)
            category_info += ' --> '.join(list([category_name.name for category_name in category_level]))
            category_info += '\n'
        category_info += '\n'

        return format_html(
            f'<pre style="width:200px; white-space: pre-wrap; word-wrap: break-word;">{category_info}</pre>')

    @admin.display(description="关键内容")
    def keyword_contents_preview(self):
        return format_html('<pre style="width:300px;white-space: pre-wrap; word-wrap: break-word;\
         overflow: hidden;display: -webkit-box;-webkit-line-clamp: 3; -webkit-box-orient: vertical;text-overflow: ellipsis;"\
         title="{}">  {}<pre/>', self.keyword_contents, self.keyword_contents)

    @admin.display(description="风险判断")
    def risk_preview(self):
        return format_html('<pre style="width:100px;white-space: pre-wrap; word-wrap: break-word;\
         overflow: hidden;display: -webkit-box;-webkit-line-clamp: 3; -webkit-box-orient: vertical;text-overflow: ellipsis;"\
         title="{}">  {}<pre/>', self.risk, self.risk)


def dynamic_upload_to(instance, filename):
    # 获取实例的属性值作为路径的一部分
    today = datetime.datetime.today()
    dynamic_path = today.strftime("%Y_%m_%d")  # 替换为你的动态字段
    # 获取文件的扩展名
    ext = os.path.splitext(filename)[1]
    # 构建最终的文件路径
    final_path = os.path.join("upload/excels", dynamic_path, filename)

    return final_path


class AIExcelFile(BaseModel):
    file = models.FileField(verbose_name="上传路径", upload_to=dynamic_upload_to)
    sync_status = models.BooleanField(verbose_name="是否已经同步", default=False)

    class Meta:
        verbose_name_plural = "上传excel文件"
        verbose_name = "上传excel文件"


@receiver(pre_delete, sender=AIExcelFile)
def delete_file(sender, instance, **kwargs):
    # 删除对应的文件
    if instance.file:
        if os.path.isfile(instance.file.path):
            os.remove(instance.file.path)


def get_article_keywords_frequency(keywords):
    queryset = ArticleKeyword.objects.filter(id__in=keywords).distinct()
    frequency_dict = {}
    for keyword in queryset:
        frequency_dict[keyword.text] = keyword.article_set.count()
    return frequency_dict
